package org.lotic.xdb.xml;

import java.io.File;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.io.SAXReader;
import org.lotic.ldk.string.StringUtil;

/**
 * XML文件操作.
 * 
 * @author lotic
 * 
 */
public class XMLHandle {
	private static final Log log = LogFactory.getLog(XMLHandle.class);
	/**
	 * 文档对象.
	 */
	private Document document;
	/**
	 * 
	 */
	private SAXReader reader;

	public XMLHandle() {

	}

	/**
	 *指定xml文件构造.
	 * @param xml
	 */
	public XMLHandle(File xml) {
		reader = new SAXReader();
		try {
			this.document = reader.read(xml);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 指定xml文件输入流构造.
	 * @param in
	 */
	public XMLHandle(InputStream in) {
		reader = new SAXReader();
		try {
			this.document = reader.read(in);
		} catch (DocumentException e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * 增加一个节点
	 * 
	 * @param parent
	 *            父节点路径.必须是单一节点.
	 * @param name
	 *            节点名称.
	 * @param attribute
	 *            节点属性map.其中key为名称 value为值
	 * @param value
	 *            节点的值.
	 */
	public Node addNode(final String parent, final String name,
			final Map attribute, final String value) {
		Element p = (Element) document.selectSingleNode(parent);
		Element e = p.addElement(name);
		Iterator<String> it = attribute.keySet().iterator();
		String key;
		while (it.hasNext()) {
			key = it.next();
			e.addAttribute(key, attribute.get(key).toString());
		}
		if (StringUtil.isNotEmptyOrNull(value)) {
			e.addText(value);
		}
		return e;

	}
	
	/**
	 * 在一个节点下增加一个子节点.
	 * @param parent 父节点
	 * @param name 节点名称.
	 * @param attribute 节点属性map. key将作为属性名称.value将作为属性值.
	 * @param value 节点值.
	 * @return 节点对象.
	 */
	public Node addNode(final Node parent,final String name,
			final Map attribute, final String value) {
		Element p = (Element)parent;
		Element e = p.addElement(name);
		Iterator<String> it = attribute.keySet().iterator();
		String key;
		while (it.hasNext()) {
			key = it.next();
			e.addAttribute(key, attribute.get(key).toString());
		}
		if (StringUtil.isNotEmptyOrNull(value)) {
			e.addText(value);
		}
		return e;
	}
	
	/**
	 * 修改节点.
	 * @param node 需要更新的节点
	 * @param attribute 节点属性数据.
	 * @param value 节点text值.
	 */
	public void updateNode(final Node node,Map attribute,String value) {
		if(node == null) {
			log.info("修改节点为空!");
			return;
		}
		Iterator it = attribute.keySet().iterator();
		String  key;
		Element e = (Element)node;
		while(it.hasNext()) {
			key = it.next().toString();
			e.attribute(key).setValue(attribute.get(key).toString());
		}
		if(StringUtil.isNotEmptyOrNull(value)) {
			e.setText(value);
		}
	}

	/**
	 * 查找节点.
	 * @param path 节点的路径.
	 * @param attrName 指定的属性名称
	 * @param attrValue 属性值.
	 * @return 找到返回节点对象.没有找到返回null.
	 */
	public Node findNode(String path, String attrName, String attrValue) {
		List<Node> nodes = document.selectNodes(path);
		Element e;
		for (Node node : nodes) {
			e = (Element) node;
			e.attributeValue(attrName);
			if (e.attributeValue(attrName).equals(attrValue)) {
				return e;
			}
			
		}
		return null;
	}
	
	/**
	 * 在一个节点下查找子节点.
	 * @param parent 父亲节点.
	 * @param nodeName 节点名称.
	 * @param attrName 指定的属性名称
	 * @param attrValue 属性值.
	 * @return 找到的节点,,没有找到返回null.
	 */
	public Node findNode (Node parent,String nodeName,String attrName, String attrValue) {
		Element pe = (Element)parent;
		if(parent == null) {
			return null;
		}
		Iterator<Element> it = pe.elementIterator();
		
		Element e ;
		while(it.hasNext()) {
			e = it.next();
			if(e.getName().equals(nodeName)
					&& e.attribute(attrName).getValue().equals(attrValue)){
				return e;
			}
		}
		return null;
	}

	public Document getDocument() {
		return document;
	}

	public void setDocument(Document document) {
		this.document = document;
	}

}
